package com.ym521.skeleton.core;

import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import androidx.annotation.ColorRes;
import androidx.annotation.IdRes;
import androidx.annotation.IntRange;
import androidx.annotation.LayoutRes;
import androidx.core.content.ContextCompat;

import com.ym521.skeleton.R;
import com.ym521.skeleton.widget.ShimmerLayout;

/**
 * update by Ym on 20223/07/30.
 */

public final class BlockViewSkeletonScreen implements SkeletonScreen {
    private final String TAG = "BlockViewSkeletonScreen";

    private final ViewReplacer mViewReplacer;
    private final View mActualView;
    private final int mSkeletonResID;
    private int[] blockViewResID;
    private final int mShimmerColor;
    private final boolean mShimmer;
    private final int mShimmerDuration;
    private final int mShimmerAngle;

    private BlockViewSkeletonScreen(Builder builder) {
        mActualView = builder.mView;
        mSkeletonResID = builder.mSkeletonLayoutResID;
        blockViewResID = builder.blockViewResID;
        mShimmer = builder.mShimmer;
        mShimmerDuration = builder.mShimmerDuration;
        mShimmerAngle = builder.mShimmerAngle;
        mShimmerColor = builder.mShimmerColor;
        mViewReplacer = new ViewReplacer(builder.mView);
    }

    private View generateShimmerContainerLayout(ViewGroup parentView) {
        ViewGroup rootView = (ViewGroup) LayoutInflater.from(mActualView.getContext()).inflate(mSkeletonResID, parentView, false);
        for (int blockViewResID : blockViewResID) {
            View blockView = rootView.findViewById(blockViewResID);
            ShimmerLayout shimmerLayout = (ShimmerLayout) LayoutInflater.from(mActualView.getContext()).inflate(R.layout.layout_shimmer, parentView, false);
            shimmerLayout.setShimmerColor(mShimmerColor);
            shimmerLayout.setShimmerAngle(mShimmerAngle);
            shimmerLayout.setShimmerAnimationDuration(mShimmerDuration);
            ViewGroup.LayoutParams lp = blockView.getLayoutParams();
            rootView.removeView(blockView);
            ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            shimmerLayout.addView(blockView, layoutParams);
            rootView.addView(shimmerLayout, lp);
            if (lp != null) {
                shimmerLayout.setLayoutParams(lp);
            }
            shimmerLayout.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
                @Override
                public void onViewAttachedToWindow(View v) {
                    shimmerLayout.startShimmerAnimation();
                }

                @Override
                public void onViewDetachedFromWindow(View v) {
                    shimmerLayout.stopShimmerAnimation();
                }
            });
            shimmerLayout.startShimmerAnimation();
        }
        return rootView;
    }

    private View generateSkeletonLoadingView() {
        ViewParent viewParent = mActualView.getParent();
        if (viewParent == null) {
            return null;
        }
        if (blockViewResID == null || blockViewResID.length == 0)
            return null;

        ViewGroup parentView = (ViewGroup) viewParent;
        if (mShimmer) {
            return generateShimmerContainerLayout(parentView);
        }
        return LayoutInflater.from(mActualView.getContext()).inflate(mSkeletonResID, parentView, false);
    }

    @Override
    public void show() {
        View skeletonLoadingView = generateSkeletonLoadingView();
        if (skeletonLoadingView != null) {
            mViewReplacer.replace(skeletonLoadingView);
        }
    }

    @Override
    public void hide() {
        dismiss();
    }

    @Override
    public void dismiss() {
        for (int resID : blockViewResID) {
            ViewGroup viewGroup = mViewReplacer.getSourceView().findViewById(resID);
            if (viewGroup == null)
                continue;
            try {
                View view = viewGroup.getChildAt(0);
                if ( view instanceof ShimmerLayout) {
                    ((ShimmerLayout) view).stopShimmerAnimation();
                }
            }catch (Exception e){
                Log.e(TAG,e.toString());
            }
        }
        mViewReplacer.restore();
    }

    public static class Builder {
        private final View mView;
        private final int mSkeletonLayoutResID;
        private int[] blockViewResID;
        private boolean mShimmer = true;
        private int mShimmerColor;
        private int mShimmerDuration = 1000;
        private int mShimmerAngle = 20;

        public Builder(View view, @LayoutRes int skeletonLayoutResID) {
            this.mView = view;
            this.mSkeletonLayoutResID = skeletonLayoutResID;
            this.mShimmerColor = ContextCompat.getColor(mView.getContext(), R.color.shimmer_color);
        }

        /**
         * @param blockViewResID 根布局下的块ID
         */
        public Builder load(@IdRes int... blockViewResID) {
            this.blockViewResID = blockViewResID;
            return this;
        }

        /**
         * @param shimmerColor the shimmer color
         */
        public Builder color(@ColorRes int shimmerColor) {
            this.mShimmerColor = ContextCompat.getColor(mView.getContext(), shimmerColor);
            return this;
        }

        /**
         * @param shimmer whether show shimmer animation
         */
        public Builder shimmer(boolean shimmer) {
            this.mShimmer = shimmer;
            return this;
        }

        /**
         * the duration of the animation , the time it will take for the highlight to move from one end of the layout
         * to the other.
         *
         * @param shimmerDuration Duration of the shimmer animation, in milliseconds
         */
        public Builder duration(int shimmerDuration) {
            this.mShimmerDuration = shimmerDuration;
            return this;
        }

        /**
         * @param shimmerAngle the angle of the shimmer effect in clockwise direction in degrees.
         */
        public Builder angle(@IntRange(from = 0, to = 30) int shimmerAngle) {
            this.mShimmerAngle = shimmerAngle;
            return this;
        }

        public BlockViewSkeletonScreen show() {
            BlockViewSkeletonScreen skeletonScreen = new BlockViewSkeletonScreen(this);
            skeletonScreen.show();
            return skeletonScreen;
        }

    }
}
